home *** CD-ROM | disk | FTP | other *** search
/ LiquidLibrary 2005 February / LiquidLibrary 2005 February - Disc 1.iso / pc / Portfolio Browser / Filters / PDF / LIB / gs_fonts.ps < prev    next >
Text File  |  2003-01-03  |  33KB  |  1,031 lines

  1. %    Copyright (C) 1990, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This software is licensed to a single customer by Artifex Software Inc.
  3. % under the terms of a specific OEM agreement.
  4.  
  5. % $RCSfile$ $Revision$
  6. % Font initialization and management code.
  7.  
  8. % Define the default font.
  9. /defaultfontname /Courier def
  10.  
  11. % Define the name of the font map file.
  12. /defaultfontmap (Fontmap) def
  13.  
  14. % ------ End of editable parameters ------ %
  15.  
  16. % Define the UniqueIDs and organization XUID assigned to Aladdin.
  17. % UniqueIDs 5,066,501 - 5,066,580 are assigned as follows:
  18. %   01 and 02 for shareware Cyrillic
  19. %   33 through 67 for Type 1 versions of the Hershey fonts
  20. % UniqueIDs 5,115,501 - 5,115,600 are currently unassigned.
  21. /AladdinEnterprisesXUID 107 def
  22.  
  23. % If SUBSTFONT is defined, make it the default font.
  24. /SUBSTFONT where { pop /defaultfontname /SUBSTFONT load def } if
  25.  
  26. % Define a reliable way of accessing FontDirectory in systemdict.
  27. /.FontDirectory
  28. { /FontDirectory .systemvar
  29. } .bind odef
  30.  
  31. % If DISKFONTS is true, we load individual CharStrings as they are needed.
  32. % (This is intended primarily for machines with very small memories.)
  33. % In this case, we define another dictionary, parallel to FontDirectory,
  34. % that retains an open file for every font loaded.
  35. /FontFileDirectory 10 dict def
  36.  
  37. % Define a temporary string for local use, since using =string
  38. % interferes with some PostScript programs.
  39. /.fonttempstring 128 string def
  40.  
  41. % Split up a search path into individual directories or files.
  42. /.pathlist        % <path> .pathlist <dir1|file1> ...
  43.  {  { dup length 0 eq { pop exit } if
  44.       .filenamelistseparator search not { exit } if
  45.       exch pop exch
  46.     }
  47.    loop
  48.  } bind def
  49.  
  50. % Load a font name -> font file name map.
  51. userdict /Fontmap .FontDirectory maxlength dict put
  52. /.loadFontmap {        % <file> .loadFontmap -
  53.         % We would like to simply execute .definefontmap as we read,
  54.         % but we have to maintain backward compatibility with an older
  55.         % specification that makes later entries override earlier
  56.         % ones within the same file.
  57.    50 dict exch .readFontmap
  58.     { .definefontmap } forall
  59. } bind def
  60. /.readFontmap {        % <dict> <file> .readFontmap <dict>
  61.     { dup token not { closefile exit } if
  62.         % stack: dict file fontname
  63.       % This is a hack to get around the absurd habit of MS-DOS editors
  64.       % of adding an EOF character at the end of the file.
  65.       dup (\032) eq { pop closefile exit } if
  66.       1 index token not
  67.        { (Fontmap entry for ) print dup =only
  68.      ( has no associated file or alias name!  Giving up.) = flush
  69.      {.readFontmap} 0 get 1 .quit
  70.        } if
  71.       dup type dup /stringtype eq exch /nametype eq or not
  72.        { (Fontmap entry for ) print 1 index =only
  73.      ( has an invalid file or alias name!  Giving up.) = flush
  74.      {.readFontmap} 0 get 1 .quit
  75.        } if
  76.         % stack: dict file fontname filename|aliasname
  77.       1 index type /stringtype eq
  78.       1 index type /nametype eq and 1 index xcheck and
  79.       1 index /run eq 2 index /.runlibfile eq or and {
  80.         % This is an inclusion entry.
  81.     pop findlibfile { exch pop } { file } ifelse
  82.     2 index exch .readFontmap pop
  83.       } {
  84.         % This is a real entry.
  85.         % Read and pop tokens until a semicolon.
  86.        { 2 index token not
  87.       { (Fontmap entry for ) print 1 index =only
  88.         ( ends prematurely!  Giving up.) = flush
  89.         {.loadFontmap} 0 get 1 .quit
  90.       } if
  91.      dup /; eq { pop 3 index 3 1 roll .growput exit } if
  92.      pop
  93.        } loop
  94.       } ifelse
  95.     } loop
  96. } bind def
  97. % Add an entry in Fontmap.  We redefine this if the Level 2
  98. % resource machinery is loaded.
  99. /.definefontmap            % <fontname> <file|alias> .definefontmap -
  100.  {        % Since Fontmap is global, make sure the values are storable.
  101.    .currentglobal 3 1 roll true .setglobal
  102.    dup type /stringtype eq
  103.     { dup .gcheck not { dup length string copy } if
  104.     }
  105.    if
  106.    Fontmap 3 -1 roll 2 copy .knownget
  107.     {        % Add an element to the end of the existing value,
  108.         % unless it's the same as the current last element.
  109.       mark exch aload pop counttomark 4 add -1 roll
  110.       2 copy eq { cleartomark pop pop } { ] readonly .growput } ifelse
  111.     }
  112.     {        % Make a new entry.
  113.       mark 4 -1 roll ] readonly .growput
  114.     }
  115.    ifelse .setglobal
  116.  } bind def
  117.  
  118. % Parse a font file just enough to find the FontName or FontType.
  119. /.findfontvalue {    % <file> <key> .findfontvalue <value> true
  120.             % <file> <key> .findfontvalue false
  121.             % Closes the file in either case.
  122.   exch dup read not { -1 } if
  123.   2 copy unread 16#80 eq {
  124.     dup (xxxxxx) readstring pop pop        % skip .PFB header
  125.   } if
  126.   {        % Stack: key file
  127.         % Protect ourselves against syntax errors here.
  128.     dup { token } stopped { pop false exit } if
  129.     not { false exit } if        % end of file
  130.     dup /eexec eq { pop false exit } if        % reached eexec section
  131.     dup /Subrs eq { pop false exit } if        % Subrs without eexec
  132.     dup /CharStrings eq { pop false exit } if    % CharStrings without eexec
  133.     dup 3 index eq
  134.      { xcheck not { dup token exit } if }    % found key
  135.      { pop }
  136.     ifelse
  137.   } loop
  138.         % Stack: key file value true   (or)
  139.         % Stack: key file false
  140.   dup { 4 } { 3 } ifelse -2 roll closefile pop
  141. } bind def
  142. /.findfontname
  143.  { /FontName .findfontvalue
  144.  } bind def
  145.  
  146. % If there is no FONTPATH, try to get one from the environment.
  147. NOFONTPATH { /FONTPATH () def } if
  148. /FONTPATH where
  149.  { pop }
  150.  { /FONTPATH (GS_FONTPATH) getenv not { () } if def }
  151. ifelse
  152. FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if
  153. /FONTPATH [ FONTPATH .pathlist ] def
  154.  
  155. % Scan directories looking for plausible fonts.  "Plausible" means that
  156. % the file begins with %!PS-AdobeFont or %!FontType1, or with \200\001
  157. % followed by four arbitrary bytes and then either of these strings.
  158. % To speed up the search, we skip any file whose name appears in
  159. % the Fontmap (with any extension and upper/lower case variation) already,
  160. % and any file whose extension definitely indicates it is not a font.
  161. %
  162. % NOTE: The current implementation of this procedure is somewhat Unix/DOS-
  163. % specific.  It assumes that '/' and '\' are directory separators, and that
  164. % the part of a file name following the last '.' is the extension.
  165. %
  166. /.lowerstring        % <string> .lowerstring <lowerstring>
  167.  { 0 1 2 index length 1 sub
  168.     { 2 copy get dup 65 ge exch 90 le and
  169.        { 2 copy 2 copy get 32 add put }
  170.      if pop
  171.     }
  172.    for
  173.  } bind def
  174. /.splitfilename {    % <dir.../base.extn> .basename <base> <extn>
  175.         % Make the file name read-only to detect aliasing bugs.
  176.         % We really don't like doing this, but we've had one
  177.         % such bug already.
  178.   readonly {
  179.     (/) search { true } { (\\) search } ifelse { pop pop } { exit } ifelse
  180.   } loop
  181.   dup { (.) search { pop pop } { exit } ifelse } loop
  182.   2 copy eq {
  183.     pop ()
  184.   } {
  185.     exch dup length 2 index length 1 add sub 0 exch getinterval exch
  186.   } ifelse
  187. } bind def
  188. /.scanfontdict 1 dict def        % establish a binding
  189. /.scanfontbegin
  190.  {    % Construct the table of all file names already in Fontmap.
  191.    currentglobal true setglobal
  192.    .scanfontdict dup maxlength Fontmap length 2 add .max .setmaxlength
  193.    Fontmap
  194.     { exch pop
  195.        { dup type /stringtype eq
  196.       { .splitfilename pop .fonttempstring copy .lowerstring cvn
  197.         .scanfontdict exch true put
  198.       }
  199.       { pop
  200.       }
  201.      ifelse
  202.        }
  203.       forall
  204.     }
  205.    forall
  206.    setglobal
  207.  } bind def
  208. /.scanfontskip mark
  209.         % Strings are converted to names anyway, so....
  210.   /afm true
  211.   /bat true
  212.   /c true
  213.   /cmd true
  214.   /com true
  215.   /dir true
  216.   /dll true
  217.   /doc true
  218.   /drv true
  219.   /exe true
  220.   /fon true
  221.   /fot true
  222.   /h true
  223.   /o true
  224.   /obj true
  225.   /pfm true
  226.   /pss true        % Adobe Multiple Master font instances
  227.   /txt true
  228. .dicttomark def
  229. /.scan1fontstring 128 string def
  230. % %%BeginFont: is not per Adobe documentation, but a few fonts have it.
  231. /.scanfontheaders [(%!PS-Adobe*) (%!FontType*) (%%BeginFont:*)] def
  232. 0 .scanfontheaders { length max } forall 6 add    % extra for PFB header
  233. /.scan1fontfirst exch string def
  234. /.scanfontdir        % <dirname> .scanfontdir -
  235.  { currentglobal exch true setglobal
  236.    QUIET not { (Scanning ) print dup print ( for fonts...) print flush } if
  237.    (*) 2 copy .filenamedirseparator
  238.    dup (\\) eq { pop (\\\\) } if    % double \ for pattern match
  239.    exch concatstrings concatstrings
  240.    0 0 0 4 -1 roll    % found scanned files
  241.     {        % stack: <fontcount> <scancount> <filecount> <filename>
  242.       exch 1 add exch                   % increment filecount
  243.       dup .splitfilename .fonttempstring copy .lowerstring
  244.         % stack: <fontcount> <scancount> <filecount+1> <filename>
  245.         %    <BASE> <ext>
  246.       .scanfontskip exch known exch .scanfontdict exch known or
  247.        { pop
  248.         % stack: <fontcount> <scancount> <filecount+1>
  249.        }
  250.        { 3 -1 roll 1 add 3 1 roll
  251.         % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  252.      dup (r) { file } .internalstopped
  253.       { pop pop null ()
  254.         % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  255.         %    null ()
  256.       }
  257.       {
  258.         % On some platforms, the file operator will open directories,
  259.         % but an error will occur if we try to read from one.
  260.         % Handle this possibility here.
  261.         dup .scan1fontfirst { readstring } .internalstopped
  262.          { pop pop () }
  263.          { pop }
  264.         ifelse
  265.         % stack: <fontcount> <scancount+1> <filecount+1>
  266.         %    <filename> <file> <header>
  267.       }
  268.      ifelse
  269.         % Check for PFB file header.
  270.      dup (\200\001????*) .stringmatch
  271.       { dup length 6 sub 6 exch getinterval }
  272.      if
  273.         % Check for font file headers.
  274.      false .scanfontheaders
  275.       { 2 index exch .stringmatch or
  276.       }
  277.      forall exch pop
  278.       {    % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  279.         %    <file>
  280.         dup 0 setfileposition .findfontname
  281.          { dup Fontmap exch known
  282.         { pop pop
  283.         }
  284.         { exch copystring exch
  285.           DEBUG { ( ) print dup =only flush } if
  286.           1 index .definefontmap
  287.           .splitfilename pop true .scanfontdict 3 1 roll .growput
  288.             % Increment fontcount.
  289.           3 -1 roll 1 add 3 1 roll
  290.         }
  291.            ifelse
  292.          }
  293.          { pop
  294.          }
  295.         ifelse
  296.       }
  297.         % .findfontname will have done a closefile in the above case.
  298.       { dup null eq { pop } { closefile } ifelse pop
  299.       }
  300.      ifelse
  301.        }
  302.       ifelse
  303.     }
  304.    .scan1fontstring filenameforall
  305.    QUIET
  306.     { pop pop pop }
  307.     { ( ) print =only ( files, ) print =only ( scanned, ) print
  308.       =only ( new fonts.) = flush
  309.     }
  310.    ifelse
  311.    setglobal
  312.  } bind def
  313.  
  314. %END FONTPATH
  315.  
  316. % Create the dictionary that registers the .buildfont procedure (called by
  317. % definefont) for each FontType.
  318. /buildfontdict 20 dict def
  319.  
  320. % Register Type 3 fonts, which are always supported, for definefont.
  321. buildfontdict 3 /.buildfont3 cvx put
  322.  
  323. % Register Type 0 fonts if they are supported.  Strictly speaking,
  324. % we should do this in its own file (gs_type0.ps), but since this is
  325. % the only thing that would be in that file, it's simpler to put it here.
  326. /.buildfont0 where { pop buildfontdict 0 /.buildfont0 cvx put } if
  327.  
  328. % Define definefont.  This is a procedure built on a set of operators
  329. % that do all the error checking and key insertion.
  330. /.growfontdict
  331.  {    % Grow the font dictionary, if necessary, to ensure room for an
  332.     % added entry, making sure there is at least one slot left for FID.
  333.    dup maxlength 1 index length sub 2 lt
  334.     { dup dup wcheck
  335.        { .growdict }
  336.        { .growdictlength dict .copydict }
  337.       ifelse
  338.     }
  339.     { dup wcheck not { dup maxlength dict .copydict } if
  340.     }
  341.    ifelse
  342.  } bind def 
  343. /.completefont {
  344.   {        % Check for disabled platform fonts.
  345.       NOPLATFONTS
  346.        {    % Make sure we leave room for FID.
  347.      .growfontdict dup /ExactSize 0 put
  348.        }
  349.        {    % Hack: if the Encoding looks like it might be the
  350.         % Symbol or Dingbats encoding, load those now (for the
  351.         % benefit of platform font matching) just in case
  352.         % the font didn't actually reference them.
  353.         % Note that some types of font don't have an Encoding.
  354.      dup /Encoding .knownget {
  355.        dup length 65 ge {
  356.          64 get
  357.          dup /congruent eq { SymbolEncoding pop } if
  358.          /a9 eq { DingbatsEncoding pop } if
  359.        } {
  360.          pop
  361.        } ifelse
  362.      } if
  363.        }
  364.       ifelse
  365.       true exch
  366.         % If this is a CIDFont, CIDFontType takes precedence
  367.         % over FontType.
  368.       dup /CIDFontType known {
  369.     /.buildcidfont where {
  370.       pop exch not exch    % true => false
  371.     } if
  372.       } if
  373.       exch {
  374.     dup /FontType get //buildfontdict exch get exec
  375.       } {
  376.     .buildcidfont
  377.       } ifelse
  378.  
  379.       DISKFONTS
  380.        { FontFileDirectory 2 index known
  381.       { dup /FontFile FontFileDirectory 4 index get .growput
  382.       }
  383.      if
  384.        }
  385.       if
  386.       readonly        % stack: name fontdict
  387.   } stopped { /invalidfont signalerror } if
  388. } bind odef
  389. /definefont
  390.  { .completefont
  391.         % If the current allocation mode is global, also enter
  392.         % the font in LocalFontDirectory.
  393.    .currentglobal
  394.     { //systemdict /LocalFontDirectory .knownget
  395.        { 2 index 2 index .growput }
  396.       if
  397.     }
  398.    if
  399.    dup .FontDirectory 4 -2 roll .growput
  400.         % If the font originated as a resource, register it.
  401.    currentfile .currentresourcefile eq { dup .registerfont } if
  402.  } odef
  403.  
  404. % Define a procedure for defining aliased fonts.
  405. % We use this only for explicitly aliased fonts, not substituted fonts:
  406. % we think this matches the observed behavior of Adobe interpreters.
  407. /.aliasfont        % <name> <font> .aliasfont <newFont>
  408.  { .currentglobal 3 1 roll dup .gcheck .setglobal
  409.    dup length 2 add dict
  410.    dup 3 -1 roll { 1 index /FID eq { pop pop } { put dup } ifelse } forall
  411.         % Stack: global fontname newfont newfont.
  412.         % We might be defining a global font whose FontName
  413.         % is a local string.  This is weird, but legal,
  414.         % and doesn't cause problems anywhere else:
  415.         % to avoid any possible problems in this case, do a cvn.
  416.         % We might also be defining (as an alias) a global font
  417.         % whose FontName is a local non-string, if someone passed a
  418.         % garbage value to findfont.  In this case, just don't
  419.         % call definefont at all.
  420.    2 index dup type /stringtype eq exch .gcheck or 1 index .gcheck not or
  421.     { /FontName 3 index dup type /stringtype eq { cvn } if put
  422.         % Don't bind in definefont, since Level 2 redefines it.
  423.       /definefont .systemvar exec
  424.     }
  425.     { .completefont pop exch pop
  426.     }
  427.    ifelse exch .setglobal
  428.  } odef        % so findfont will bind it
  429.  
  430. % Define .loadfontfile for loading a font.  If we recognize Type 1 and/or
  431. % TrueType fonts, gs_type1.ps and/or gs_ttf.ps will redefine this.
  432. /.loadfontfile {
  433.         % According to Ed Taft, Adobe interpreters push userdict
  434.         % before loading a font, and pop it afterwards.
  435.   userdict begin
  436.     cvx exec
  437.   end
  438. } bind def
  439. /.loadfont
  440.  {        % Some buggy fonts leave extra junk on the stack,
  441.         % so we have to make a closure that records the stack depth
  442.         % in a fail-safe way.
  443.    {{.loadfontfile} .execasresource} count 1 sub 2 .execn
  444.    count exch sub { pop } repeat
  445.  } bind def
  446.  
  447. % Find an alternate font to substitute for an unknown one.
  448. % We go to some trouble to parse the font name and extract
  449. % properties from it.  Later entries take priority over earlier.
  450. /.substitutefaces [
  451.     % Guess at suitable substitutions for random unknown fonts.
  452.   [(Book) /NewCenturySchlbk 0]
  453.   [(Grot) /Helvetica 0]
  454.   [(Roman) /Times 0]
  455.   [(Chancery) /ZapfChancery-MediumItalic 0]
  456.     % If the family name appears in the font name,
  457.     % use a font from that family.
  458.   [(Arial) /Helvetica 0]
  459.   [(Avant) /AvantGarde 0]
  460.   [(Bookman) /Bookman 0]
  461.   [(Century) /NewCenturySchlbk 0]
  462.   [(Cour) /Courier 0]
  463.   [(Frut) /Helvetica 0]
  464.   [(Garamond) /Palatino 0]
  465.   [(Geneva) /Helvetica 0]
  466.   [(Helv) /Helvetica 0]
  467.   [(NewYork) /Bookman 0]
  468.   [(Pala) /Palatino 0]
  469.   [(Schlbk) /NewCenturySchlbk 0]
  470.   [(Swiss) /Helvetica 0]
  471.   [(Symbol) /Symbol 0]
  472.   [(Times) /Times 0]
  473.     % Substitute for Adobe Multiple Master fonts.
  474.   [(Minion) /Times 0]
  475.   [(Myriad) /Helvetica 0]
  476.     % If the font wants to be monospace, use Courier.
  477.   [(Monospace) /Courier 0]
  478.   [(Typewriter) /Courier 0]
  479.     % Define substitutes for the other Adobe PostScript 3 fonts.
  480.     % For some of them, the substitution is pretty bad!
  481.   [(Albertus) /Palatino 0]
  482.   [(AntiqueOlive) /Helvetica 0]
  483.   [(Bodoni) /NewCenturySchlbk 0]
  484.   [(Chicago) /Helvetica 2]
  485.   [(Clarendon) /Bookman 0]
  486.   [(Cooper) /NewCenturySchlbk 0]
  487.   [(Copperplate) /AvantGarde 0]    % inappropriate, small-cap font
  488.   [(Coronet) /ZapfChancery-MediumItalic 0]
  489.   [(Eurostile) /Helvetica 0]
  490.   [(Geneva) /Courier 2]        % should be fixed-pitch sans demi
  491.   [(GillSans) /Helvetica 2]
  492.   [(GillSans-Light) /Helvetica 0]
  493.   [(Goudy) /Palatino 0]
  494.   [(Hoefler) /NewCenturySchlbk 0]
  495.   [(Joanna) /Times 0]
  496.   [(LetterGothic) /Courier 0]    % should be fixed-pitch sans
  497.   [(LubalinGraph-Book) /Bookman 2]
  498.   [(LubalinGraph-Demi) /Bookman 0]
  499.   [(Marigold) /ZapfChancery-MediumItalic 0]
  500.   [(MonaLisa-Recut) /Palatino 0]    % inappropriate
  501.   [(Monaco) /Courier 2]        % should be fixed-pitch sans demi
  502.   [(Optima) /Helvetica 0]
  503.   [(Oxford) /ZapfChancery-MediumItalic 0]
  504.   [(Tekton) /Helvetica 0]
  505.   [(Univers) /Helvetica 0]
  506. ] readonly def
  507. /.substituteproperties [
  508.   [(It) 9] [(Oblique) 1]
  509.   [(Black) 2] [(Bd) 2] [(Bold) 2] [(bold) 2] [(Demi) 2] [(Heavy) 2] [(Sb) 2]
  510.   [(Cn) 4] [(Cond) 4] [(Narrow) 4] [(Pkg) 4] [(Compr) 4]
  511.   [(Serif) 8] [(Sans) -8]
  512. ] readonly def
  513. /.fontnameproperties {        % <int> <string|name> .fontnameproperties
  514.                 %   <int'>
  515.   .fontnamestring
  516.   .substituteproperties {
  517.     2 copy 0 get search {
  518.       pop pop pop dup length 1 sub 1 exch getinterval 3 -1 roll exch {
  519.     dup 0 ge { or } { neg not and } ifelse
  520.       } forall exch
  521.     } {
  522.       pop pop
  523.     } ifelse
  524.   } forall pop
  525. } bind def
  526. /.substitutefamilies mark
  527.   /AvantGarde
  528.     {/AvantGarde-Book /AvantGarde-BookOblique
  529.      /AvantGarde-Demi /AvantGarde-DemiOblique}
  530.   /Bookman
  531.     {/Bookman-Demi /Bookman-DemiItalic /Bookman-Light /Bookman-LightItalic}
  532.   /Courier
  533.     {/Courier /Courier-Oblique /Courier-Bold /Courier-BoldOblique}
  534.   /Helvetica
  535.     {/Helvetica /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique
  536.      /Helvetica-Narrow /Helvetica-Narrow-Oblique
  537.      /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique}
  538.   /NewCenturySchlbk
  539.     {/NewCenturySchlbk-Roman /NewCenturySchlbk-Italic
  540.      /NewCenturySchlbk-Bold /NewCenturySchlbk-BoldItalic}
  541.   /Palatino
  542.     {/Palatino-Roman /Palatino-Italic /Palatino-Bold /Palatino-BoldItalic}
  543.   /Symbol
  544.     {/Symbol /Symbol /Symbol /Symbol}
  545.   /Times
  546.     {/Times-Roman /Times-Italic /Times-Bold /Times-BoldItalic}
  547.   /ZapfChancery-MediumItalic
  548.     {/ZapfChancery-MediumItalic}
  549. .dicttomark readonly def
  550. /.nametostring {        % <name> .nametostring <string>
  551.                 % <other> .nametostring <other>
  552.   dup type /nametype eq { .namestring } if
  553. } bind def
  554. /.fontnamestring {        % <fontname> .fontnamestring <string|name>
  555.   dup type dup /nametype eq {
  556.     pop .namestring
  557.   } {
  558.     /stringtype ne { pop () } if
  559.   } ifelse
  560. } bind def
  561. /.substitutefontname {        % <fontname> <properties> .substitutefontname
  562.                 %   <altname|null>
  563.     % Look for properties and/or a face name in the font name.
  564.     % If we find any, use Times (serif) or Helvetica (sans) as the
  565.     % base font; otherwise, use the default font.
  566.     % Note that the "substituted" font name may be the same as
  567.     % the requested one; the caller must check this.
  568.   exch .fontnamestring {
  569.     defaultfontname /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique
  570.     /Helvetica-Narrow /Helvetica-Narrow-Oblique
  571.     /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique
  572.     /Times-Roman /Times-Italic /Times-Bold /Times-BoldItalic
  573.     /Helvetica-Narrow /Helvetica-Narrow-Oblique
  574.     /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique
  575.   } 3 1 roll
  576.     % Stack: facelist properties fontname
  577.     % Look for a face name.
  578.   .substitutefaces {
  579.     2 copy 0 get search {
  580.       pop pop pop
  581.     % Stack: facelist properties fontname [(pattern) family properties]
  582.       dup 2 get 4 -1 roll or 3 1 roll
  583.       1 get .substitutefamilies exch get
  584.       4 -1 roll pop 3 1 roll
  585.     } {
  586.       pop pop
  587.     } ifelse
  588.   } forall pop
  589.   1 index length mod get exec
  590. } bind def
  591. /.substitutefont {        % <fontname> .substitutefont <altname>
  592.   dup 0 exch .fontnameproperties .substitutefontname
  593.     % Only accept fonts known in the Fontmap.
  594.    Fontmap 1 index known not { pop defaultfontname } if
  595. } bind def
  596.  
  597. % If requested, make (and recognize) fake entries in FontDirectory for fonts
  598. % present in Fontmap but not actually loaded.  Thanks to Ray Johnston for
  599. % the idea behind this code.
  600. FAKEFONTS not { (%END FAKEFONTS) .skipeof } if
  601.  
  602. % We use the presence or absence of the FontMatrix key to indicate whether
  603. % a font is real or fake.  We must pop the arguments at the very end,
  604. % so that stack protection will be effective.
  605.  
  606. /definefont {        % <name> <font> definefont <font>
  607.   dup /FontMatrix known {
  608.     //definefont
  609.   } {
  610.     2 copy /FontName get findfont //definefont exch pop exch pop
  611.   } ifelse
  612. } bind odef
  613.  
  614. /scalefont {        % <font> <scale> scalefont <font>
  615.   1 index /FontMatrix known {
  616.     //scalefont
  617.   } {
  618.     1 index /FontName get findfont 1 index //scalefont
  619.     exch pop exch pop
  620.   } ifelse
  621. } bind odef
  622.  
  623. /makefont {        % <font> <matrix> makefont <font>
  624.   1 index /FontMatrix known {
  625.     //makefont
  626.   } {
  627.     1 index /FontName get findfont 1 index //makefont
  628.     exch pop exch pop
  629.   } ifelse
  630. } bind odef
  631.  
  632. /setfont {        % <font> setfont -
  633.   dup /FontMatrix known {
  634.     //setfont
  635.   } {
  636.     dup /FontName get findfont //setfont pop
  637.   } ifelse
  638. } bind odef
  639.  
  640. %END FAKEFONTS
  641.  
  642. % Define findfont so it tries to load a font if it's not found.
  643. % The Red Book requires that findfont be a procedure, not an operator,
  644. % but it still needs to restore the stacks reliably if it fails,
  645. % so we do all the work in an operator.
  646. /.findfont {
  647.   mark 1 index
  648.   //systemdict begin .dofindfont
  649.     % Define any needed aliases.
  650.   counttomark 1 sub { .aliasfont } repeat end
  651.   exch pop exch pop
  652. } odef
  653. /findfont {
  654.   .findfont
  655. } bind def
  656. % Check whether the font name we are about to look for is already on the list
  657. % of aliases we're accumulating; if so, cause an error.
  658. /.checkalias        % -mark- <alias1> ... <name> .checkalias <<same>>
  659.  { counttomark 1 sub -1 1
  660.     { index 1 index eq
  661.        { pop QUIET not
  662.       { (Unable to substitute for font.) = flush
  663.       } if
  664.      /findfont cvx /invalidfont signalerror
  665.        }
  666.       if
  667.     }
  668.    for
  669.  } bind def
  670. % Get a (non-fake) font if present in a FontDirectory.
  671. /.fontknownget        % <fontdir> <fontname> .fontknownget <font> true
  672.             % <fontdir> <fontname> .fontknownget false
  673.  { .knownget
  674.     { FAKEFONTS
  675.        { dup /FontMatrix known { true } { pop false } ifelse }
  676.        { true }
  677.       ifelse
  678.     }
  679.     { false
  680.     }
  681.    ifelse
  682.  } bind def
  683. % This is the standard procedure for handling font substitution.
  684. % Its location is per an Adobe newsgroup posting.
  685. % It is called with the font name on the stack, standing in for findfont.
  686. /.stdsubstfont {    % mark <alias1> ... <fontname> .stdsubstfont <font>
  687.       /SUBSTFONT where {
  688.     pop QUIET not {
  689.       (Substituting for font ) print dup =only
  690.       (.) = flush
  691.     } if
  692.             % No aliasing.
  693.     cleartomark mark defaultfontname
  694.       } {
  695.     dup .substitutefont
  696.     2 copy eq { pop defaultfontname } if
  697.     .checkalias
  698.     QUIET not {
  699.       SHORTERRORS {
  700.         (%%[) print 1 index =only
  701.         ( not found, substituting ) print dup =only (]%%)
  702.       } {
  703.         (Substituting font ) print dup =only
  704.         ( for ) print 1 index =only (.)
  705.       } ifelse = flush
  706.     } if
  707.             % Remove all the accumulated aliases.
  708.     counttomark 1 add 1 roll cleartomark mark exch
  709.       } ifelse
  710.   .dofindfont
  711. } bind def
  712. $error /SubstituteFont { .stdsubstfont } put
  713. % Scan the next directory on FONTPATH.
  714. /.scannextfontdir {    % - .scannextfontdir <bool>
  715.             % If we haven't scanned all the directories in
  716.             % FONTPATH, scan the next one.
  717.   null 0 1 FONTPATH length 1 sub {
  718.     FONTPATH 1 index get null ne { exch pop exit } if pop
  719.   } for dup null ne {
  720.     dup 0 eq { .scanfontbegin } if
  721.     FONTPATH 1 index get .scanfontdir
  722.     FONTPATH exch null put true
  723.   } {
  724.     pop false
  725.   } ifelse
  726. } bind def
  727. % Do the work of findfont, including substitution, defaulting, and
  728. % scanning of FONTPATH.
  729. /.dofindfont {        % <fontname> .dofindfont <font>
  730.   .tryfindfont not {
  731.             % We didn't find the font.  If we haven't scanned
  732.             % all the directories in FONTPATH, scan the next one
  733.             % now and look for the font again.
  734.     .scannextfontdir {
  735.             % Start over with an empty alias list.
  736.       counttomark 1 sub { pop } repeat
  737.       .dofindfont
  738.     } {
  739.             % No luck.  Make sure we're not already
  740.             % looking for the default font.
  741.       dup defaultfontname eq {
  742.     QUIET not {
  743.       (Unable to load default font ) print
  744.       dup =only (!  Giving up.) = flush
  745.     } if
  746.     /findfont cvx /invalidfont signalerror
  747.       } if
  748.             % Substitute for the font.  Don't alias.
  749.       $error /SubstituteFont get exec
  750.     } ifelse
  751.   } if
  752. } bind def
  753. % Try to find a font using only the present contents of Fontmap.
  754. /.tryfindfont {        % <fontname> .tryfindfont <font> true
  755.             % <fontname> .tryfindfont false
  756.   .FontDirectory 1 index .fontknownget
  757.     {            % Already loaded
  758.       exch pop true
  759.     }
  760.     { dup Fontmap exch .knownget not
  761.        {        % Unknown font name.  Look for a file with the
  762.             % same name as the requested font.
  763.      .tryloadfont
  764.        }
  765.        {        % Try each element of the Fontmap in turn.
  766.      false exch    % (in case we exhaust the list)
  767.             % Stack: fontname false fontmaplist
  768.      { exch pop
  769.        dup type /nametype eq
  770.         {            % Font alias
  771.           .checkalias .tryfindfont exit
  772.         }
  773.         { dup dup type dup /arraytype eq exch /packedarraytype eq or exch xcheck and
  774.            {        % Font with a procedural definition
  775.          exec        % The procedure will load the font.
  776.                 % Check to make sure this really happened.
  777.          .FontDirectory 1 index .knownget
  778.           { exch pop true exit }
  779.          if
  780.            }
  781.            {        % Font file name
  782.          .loadfontloop { true exit } if
  783.            }
  784.           ifelse
  785.         }
  786.        ifelse false
  787.      }
  788.      forall
  789.             % Stack: font true -or- fontname false
  790.      { true
  791.      }
  792.      {            % None of the Fontmap entries worked.
  793.                 % Try loading a file with the same name
  794.                 % as the requested font.
  795.        .tryloadfont
  796.      }
  797.     ifelse
  798.        }
  799.       ifelse
  800.     }
  801.    ifelse
  802.  } bind def
  803. % Attempt to load a font from a file.
  804. /.tryloadfont {        % <fontname> .tryloadfont <font> true
  805.             % <fontname> .tryloadfont false
  806.   dup .nametostring
  807.         % Hack: check for the presence of the resource machinery.
  808.   /.genericrfn where {
  809.     pop
  810.     2 copy .fonttempstring /FontResourceDir getsystemparam .genericrfn
  811.     .loadfontloop {
  812.       exch pop exch pop true
  813.     } {
  814.       dup .nametostring .loadfontloop
  815.     } ifelse
  816.   } {
  817.     .loadfontloop
  818.   } ifelse
  819. } bind def
  820. /.loadfontloop {    % <fontname> <filename> .loadfontloop
  821.             %   <font> true
  822.             % -or-
  823.             %   <fontname> false
  824.             % See above regarding the use of 'loop'.
  825.     {
  826.             % Is the font name a string?
  827.     dup type /stringtype ne
  828.      { QUIET not
  829.         { (Can't find font with non-string name: ) print dup =only (.) = flush
  830.         }
  831.        if pop false exit
  832.      }
  833.     if
  834.             % Can we open the file?
  835.     findlibfile not
  836.      { QUIET not
  837.         { (Can't find \(or can't open\) font file ) print dup print
  838.           (.) = flush
  839.         }
  840.        if pop false exit
  841.      }
  842.     if
  843.  
  844.             % Stack: fontname fontfilename fontfile
  845.     DISKFONTS
  846.      { .currentglobal true .setglobal
  847.        2 index (r) file
  848.        FontFileDirectory exch 5 index exch .growput
  849.        .setglobal
  850.      }
  851.     if
  852.     QUIET not
  853.      { (Loading ) print 2 index =only
  854.        ( font from ) print 1 index print (... ) print flush
  855.      }
  856.     if
  857.     % If LOCALFONTS isn't set, load the font into local or global
  858.     % VM according to FontType; if LOCALFONTS is set, load the font
  859.     % into the current VM, which is what Adobe printers (but not
  860.     % DPS or CPSI) do.
  861.     LOCALFONTS { false } { /setglobal where } ifelse
  862.      { pop /FontType .findfontvalue { 1 eq } { false } ifelse
  863.         % .setglobal, like setglobal, aliases FontDirectory to
  864.         % GlobalFontDirectory if appropriate.  However, we mustn't
  865.         % allow the current version of .setglobal to be bound in,
  866.         % because it's different depending on language level.
  867.        .currentglobal exch /.setglobal .systemvar exec
  868.         % Remove the fake definition, if any.
  869.        .FontDirectory 3 index .undef
  870.        1 index (r) file .loadfont .FontDirectory exch
  871.        /.setglobal .systemvar exec
  872.      }
  873.      { .loadfont .FontDirectory
  874.      }
  875.     ifelse
  876.         % Stack: fontname fontfilename fontdirectory
  877.     QUIET not
  878.      { //systemdict /level2dict known
  879.         { .currentglobal false .setglobal vmstatus
  880.           true .setglobal vmstatus 3 -1 roll pop
  881.           6 -1 roll .setglobal 5
  882.         }
  883.         { vmstatus 3
  884.         }
  885.        ifelse { =only ( ) print } repeat
  886.        (done.) = flush
  887.      } if
  888.  
  889.         % Check to make sure the font was actually loaded.
  890.     dup 3 index .fontknownget
  891.      { 4 1 roll pop pop pop true exit } if
  892.  
  893.         % Maybe the file had a different FontName.
  894.         % See if we can get a FontName from the file, and if so,
  895.         % whether a font by that name exists now.
  896.     exch (r) file .findfontname
  897.      { 2 copy .fontknownget
  898.         {    % Yes.  Stack: origfontname fontdirectory filefontname fontdict
  899.           3 -1 roll pop exch
  900.           QUIET
  901.            { pop
  902.            }
  903.            { (Using ) print =only
  904.              ( font for ) print 1 index =only
  905.              (.) = flush
  906.            }
  907.           ifelse true exit
  908.         }
  909.        if pop
  910.      }
  911.     if pop
  912.  
  913.         % The font definitely did not load correctly.
  914.     QUIET not
  915.      { (Loading ) print dup =only
  916.        ( font failed.) = flush
  917.      } if
  918.     false exit
  919.  
  920.     } loop        % end of loop
  921.  
  922.  } bind def
  923.  
  924. % Define a procedure to load all known fonts.
  925. % This isn't likely to be very useful.
  926. /loadallfonts
  927.  { Fontmap { pop findfont pop } forall
  928.  } bind def
  929.  
  930. % If requested, load all the fonts defined in the Fontmap into FontDirectory
  931. % as "fake" fonts i.e., font dicts with only FontName and FontType defined.
  932. % (We define FontType only for the sake of some questionable code in the
  933. % Apple Printer Utility 2.0 font inquiry code.)
  934. %
  935. % Note that this procedure only creates fake fonts in the FontDirectory
  936. % associated with the current VM.  This is because in multi-context systems,
  937. % creating the fake fonts in local VM leads to undesirable complications.
  938. /.definefakefonts
  939.     {
  940.     }
  941.     {
  942.       (gs_fonts FAKEFONTS) VMDEBUG
  943.       Fontmap {
  944.     pop dup type /stringtype eq { cvn } if
  945.     .FontDirectory 1 index known not {
  946.       2 dict dup /FontName 3 index put
  947.       dup /FontType 1 put
  948.       .FontDirectory 3 1 roll put
  949.     } {
  950.       pop
  951.     } ifelse
  952.       } forall
  953.     }
  954. FAKEFONTS { exch } if pop def    % don't bind, .current/setglobal get redefined
  955.  
  956. % Install initial fonts from Fontmap.
  957. /.loadinitialfonts
  958.  { NOFONTMAP not
  959.     { /FONTMAP where
  960.       { pop [ FONTMAP .pathlist ]
  961.          { dup VMDEBUG findlibfile
  962.         { exch pop .loadFontmap }
  963.         { /undefinedfilename signalerror }
  964.            ifelse
  965.          }
  966.       }
  967.       { LIBPATH
  968.          { defaultfontmap 2 copy .filenamedirseparator
  969.            exch concatstrings concatstrings dup VMDEBUG
  970.            (r) { file } .internalstopped
  971.         { pop pop } { .loadFontmap } ifelse
  972.          }
  973.       }
  974.      ifelse forall
  975.     }
  976.    if
  977.    .definefakefonts    % current VM is global
  978.  } def            % don't bind, .current/setglobal get redefined
  979.  
  980. % ---------------- Synthetic font support ---------------- %
  981.  
  982. % Create a new font by modifying an existing one.  paramdict contains
  983. % entries with the same keys as the ones found in a Type 1 font;
  984. % it should also contain enough empty entries to allow adding the
  985. % corresponding non-overridden entries from the original font dictionary,
  986. % including FID.  If paramdict includes a FontInfo entry, this will
  987. % also override the original font's FontInfo, entry by entry;
  988. % again, it must contain enough empty entries.
  989.  
  990. % Note that this procedure does not perform a definefont.
  991.  
  992. /.makemodifiedfont    % <fontdict> <paramdict> .makemodifiedfont <fontdict'>
  993.  { exch
  994.     {            % Stack: destdict key value
  995.       1 index /FID ne
  996.        { 2 index 2 index known
  997.       {        % Skip fontdict entry supplied in paramdict, but
  998.             % handle FontInfo specially.
  999.         1 index /FontInfo eq
  1000.          { 2 index 2 index get        % new FontInfo
  1001.            1 index                % old FontInfo
  1002.         {    % Stack: destdict key value destinfo key value
  1003.           2 index 2 index known
  1004.            { pop pop }
  1005.            { 2 index 3 1 roll put }
  1006.           ifelse
  1007.         }
  1008.            forall pop
  1009.          }
  1010.         if
  1011.       }
  1012.       {        % No override, copy the fontdict entry.
  1013.         2 index 3 1 roll put
  1014.         dup dup    % to match pop pop below
  1015.       }
  1016.      ifelse
  1017.        }
  1018.       if
  1019.       pop pop
  1020.     } forall
  1021.  } bind def
  1022.  
  1023. % Make a modified font and define it.  Note that unlike definefont,
  1024. % this does not leave the font on the operand stack.
  1025.  
  1026. /.definemodifiedfont    % <fontdict> <paramdict> .definemodifiedfont -
  1027.  { .makemodifiedfont
  1028.    dup /FontName get exch definefont pop
  1029.  } bind def
  1030.